/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "map.h"

void FreeMapNode( void *pv )
{
	struct MapNode		*node = (struct MapNode *) pv ;
	
	DestroyObject( GetZlangRuntime() , node->key );
	DestroyObject( GetZlangRuntime() , node->value );
	ZLFREE( node );
	
	return;
}

static int CalcObjectMapKeyId( struct ZlangRuntime *rt , struct ZlangObject *obj , uint64_t *p_map_key_id )
{
	if( IsTypeOf( rt , obj , GetStringObjectInRuntimeObjectsHeap(rt) ) )
	{
		uint64_t	id = 0 ;
		unsigned char	*str = NULL ;
		int32_t		str_len ;
		unsigned char	*p = NULL ;
		int32_t		l ;
		
		CallRuntimeFunction_string_GetStringValue( rt , obj , (char **) & str , & str_len );
		for( p = str , l = 0 ; l < str_len ; p++ , l++ )
		{
			id = id * 31 + (*p) ;
		}
		
		if( p_map_key_id )
			(*p_map_key_id) = id ;
	}
	else if( IsTypeOf( rt , obj , GetBoolObjectInRuntimeObjectsHeap(rt) ) )
	{
		unsigned char	b ;
		CallRuntimeFunction_bool_GetBoolValue( rt , obj , & b );
		if( p_map_key_id )
			(*p_map_key_id) = (uint64_t)b ;
	}
	else if( IsTypeOf( rt , obj , GetShortObjectInRuntimeObjectsHeap(rt) ) )
	{
		int16_t		s ;
		CallRuntimeFunction_short_GetShortValue( rt , obj , & s );
		if( p_map_key_id )
			(*p_map_key_id) = (uint64_t)s ;
	}
	else if( IsTypeOf( rt , obj , GetUShortObjectInRuntimeObjectsHeap(rt) ) )
	{
		uint16_t	us ;
		CallRuntimeFunction_ushort_GetUShortValue( rt , obj , & us );
		if( p_map_key_id )
			(*p_map_key_id) = (uint16_t)us ;
	}
	else if( IsTypeOf( rt , obj , GetIntObjectInRuntimeObjectsHeap(rt) ) )
	{
		int32_t		i ;
		CallRuntimeFunction_int_GetIntValue( rt , obj , & i );
		if( p_map_key_id )
			(*p_map_key_id) = (uint64_t)i ;
	}
	else if( IsTypeOf( rt , obj , GetUIntObjectInRuntimeObjectsHeap(rt) ) )
	{
		uint32_t	ui ;
		CallRuntimeFunction_uint_GetUIntValue( rt , obj , & ui );
		if( p_map_key_id )
			(*p_map_key_id) = (uint32_t)ui ;
	}
	else if( IsTypeOf( rt , obj , GetLongObjectInRuntimeObjectsHeap(rt) ) )
	{
		int64_t		l ;
		CallRuntimeFunction_long_GetLongValue( rt , obj , & l );
		if( p_map_key_id )
			(*p_map_key_id) = (uint64_t)l ;
	}
	else if( IsTypeOf( rt , obj , GetULongObjectInRuntimeObjectsHeap(rt) ) )
	{
		uint64_t	ul ;
		CallRuntimeFunction_ulong_GetULongValue( rt , obj , & ul );
		if( p_map_key_id )
			(*p_map_key_id) = (uint64_t)ul ;
	}
	else if( IsTypeOf( rt , obj , GetFloatObjectInRuntimeObjectsHeap(rt) ) )
	{
		float		f ;
		unsigned char	*p_f = (unsigned char *) & f ;
		uint64_t	key_id = 0 ;
		unsigned char	*p_key_id = (unsigned char *) & key_id ;
		CallRuntimeFunction_float_GetFloatValue( rt , obj , & f );
		p_key_id[4] = p_f[0] ;
		p_key_id[5] = p_f[1] ;
		p_key_id[6] = p_f[2] ;
		p_key_id[7] = p_f[3] ;
		if( p_map_key_id )
			(*p_map_key_id) = key_id ;
	}
	else if( IsTypeOf( rt , obj , GetDoubleObjectInRuntimeObjectsHeap(rt) ) )
	{
		double		d ;
		unsigned char	*p_d = (unsigned char *) & d ;
		uint64_t	key_id = 0 ;
		unsigned char	*p_key_id = (unsigned char *) & key_id ;
		CallRuntimeFunction_double_GetDoubleValue( rt , obj , & d );
		p_key_id[0] = p_d[0] ;
		p_key_id[1] = p_d[1] ;
		p_key_id[2] = p_d[2] ;
		p_key_id[3] = p_d[3] ;
		p_key_id[4] = p_d[4] ;
		p_key_id[5] = p_d[5] ;
		p_key_id[6] = p_d[6] ;
		p_key_id[7] = p_d[7] ;
		if( p_map_key_id )
			(*p_map_key_id) = key_id ;
	}
	else
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_MAP_KEY_TYPE_NOT_SUPPORTED , "map key type[%s] not supported" , GetCloneObjectName(obj) )
		return ZLANG_ERROR_MAP_KEY_TYPE_NOT_SUPPORTED;
	}
	
	return 0;
}

ZlangDirectFunction_map_Put map_Put;
int map_Put( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject *key , struct ZlangObject *value , struct ZlangObject **add )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	char				*ext_obj_name = NULL ;
	char				*ext_obj2_name = NULL ;
	char				*key_tpye_name = NULL ;
	char				*value_tpye_name = NULL ;
	struct MapNode			*map_node = NULL ;
	int				nret = 0 ;
	
	/*
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "key_id[%"PRIu64"]" , map_node->map_key_id )
	*/
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	ext_obj_name = GetObjectEmbellishName( obj ) ;
	ext_obj2_name = GetObjectEmbellishName2( obj ) ;
	key_tpye_name = GetCloneObjectName( key ) ;
	value_tpye_name = GetCloneObjectName( value ) ;
	if( ext_obj_name == NULL )
	{
		;
	}
	else if( ext_obj_name && ext_obj2_name == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "map expect two ext objects but one '%s'" , ext_obj_name )
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_SYNTAX;
	}
	else if( ext_obj2_name )
	{
		if( key_tpye_name == NULL || value_tpye_name == NULL || STRCMP( ext_obj_name , != , key_tpye_name ) || STRCMP( ext_obj2_name , != , value_tpye_name ) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "object type not matched" )
			IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
			return -ZLANG_ERROR_TYPE_OF_OBJECT_NOT_MATCHED;
		}
	}
	
	map_node = (struct MapNode *)ZLMALLOC( sizeof(struct MapNode) ) ;
	if( map_node == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for map node" )
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_ALLOC;
	}
	memset( map_node , 0x00 , sizeof(struct MapNode) );
	
	nret = CalcObjectMapKeyId( rt , key , & (map_node->map_key_id) ) ;
	if( nret )
	{
		ZLFREE( map_node );
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return nret;
	}
	
	map_node->key = AllocObject( rt ) ;
	if( map_node->key == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for object" )
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_ALLOC;
	}
	
	nret = ReferObject( rt , map_node->key , key ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "ReferObject failed[%d]" , nret )
		DestroyObject( rt , map_node->key );
		ZLFREE( map_node );
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return nret;
	}
	
	nret = SetObjectName( rt , map_node->key , GetObjectName(key) ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SetObjectName failed[%d]" , nret )
		DestroyObject( rt , map_node->key );
		ZLFREE( map_node );
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return nret;
	}
	
	map_node->value = AllocObject( rt ) ;
	if( map_node->value == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for object" )
		DestroyObject( rt , map_node->key );
		ZLFREE( map_node );
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_ALLOC;
	}
	
	nret = ReferObject( rt , map_node->value , value ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "ReferObject failed[%d]" , nret )
		DestroyObject( rt , map_node->key );
		DestroyObject( rt , map_node->value );
		ZLFREE( map_node );
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return nret;
	}
	
	nret = SetObjectName( rt , map_node->value , GetObjectName(value) ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SetObjectName failed[%d]" , nret )
		DestroyObject( rt , map_node->key );
		DestroyObject( rt , map_node->value );
		ZLFREE( map_node );
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return nret;
	}
	
	nret = LinkMapTreeNodeByKeyId( map_direct_prop , map_node ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "add key_id[%"PRIu64"]  to map[%p][%p] failed[%d]" , map_node->map_key_id , obj , map_direct_prop , nret )
		DestroyObject( rt , map_node->key );
		DestroyObject( rt , map_node->value );
		ZLFREE( map_node );
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_INVOKE_METHOD_RETURN;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "add key_id[%"PRIu64"] to map[%p][%p] ok" , map_node->map_key_id , obj , map_direct_prop )
	
	map_direct_prop->map_length++;
	
	if( add )
		(*add) = map_node->value ;
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_map_Put_object_object;
int ZlangInvokeFunction_map_Put_object_object( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject		*in1_obj = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*in2_obj = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject		*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	int				nret = 0 ;
	
	nret = map_Put( rt , obj , in1_obj , in2_obj , NULL ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , FALSE );
		if( nret < 0 )
			return ThrowFatalException( rt , nret , EXCEPTION_MESSAGE_GENERAL_ERROR );
		else
			return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , TRUE );
	return 0;
}

ZlangDirectFunction_map_Get map_Get;
int map_Get( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject *key , struct ZlangObject **value )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	struct MapNode			m ;
	struct MapNode			*map_node = NULL ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	if( obj == NULL || IsObjectPropertiesEntityNull(obj) )
	{
		if( value )
			(*value) = NULL ;
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return 0;
	}
	
	memset( & m , 0x00 , sizeof(struct MapNode) );
	nret = CalcObjectMapKeyId( rt , key , & (m.map_key_id) ) ;
	if( nret )
	{
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_INVOKE_METHOD_RETURN;
	}
	
	/*
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "key_id[%"PRIu64"]" , m.map_key_id )
	*/
	
	map_node = QueryMapTreeNodeByKeyId( map_direct_prop , & m ) ;
	if( map_node == NULL )
	{
		if( value )
			(*value) = NULL ;
	}
	else
	{
		if( value )
			(*value) = map_node->value ;
		/*
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "value[%p]" , value )
		*/
	}
	
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_map_Get_object;
int ZlangInvokeFunction_map_Get_object( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject		*in1_obj = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*value = NULL ;
	int				nret = 0 ;
	
	nret = map_Get( rt , obj , in1_obj , & value ) ;
	if( nret )
	{
		UnreferObject( rt , out1_obj );
	}
	
	if( value == NULL )
	{
		UnreferObject( rt , out1_obj );
		return ThrowErrorException( rt , EXCEPTION_CODE_GENERAL , EXCEPTION_MESSAGE_MAP_GET_ERROR );
	}
	else
	{
		nret = ReferObject( rt , out1_obj , value ) ;
		if( nret )
			return ThrowFatalException( rt , nret , EXCEPTION_MESSAGE_GENERAL_ERROR );
	}
	
	return 0;
}

ZlangDirectFunction_map_TravelNextKey map_TravelNextKey;
int map_TravelNextKey( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject **key )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	struct MapNode			m ;
	struct MapNode			*map_node = NULL ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	if( (*key) == NULL || IsObjectPropertiesEntityNull(*key) )
	{
		map_node = TravelMapTreeNodeByKeyId( map_direct_prop , NULL ) ;
	}
	else
	{
		memset( & m , 0x00 , sizeof(struct MapNode) );
		nret = CalcObjectMapKeyId( rt , (*key) , & (m.map_key_id) ) ;
		if( nret )
		{
			if( key )
				(*key) = NULL ;
			IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
			return ZLANG_ERROR_INVOKE_METHOD_RETURN;
		}
		
		map_node = QueryMapTreeNodeByKeyId( map_direct_prop , & m ) ;
		if( map_node )
		{
			map_node = TravelMapTreeNodeByKeyId( map_direct_prop , map_node ) ;
		}
	}
	if( map_node == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "travel none item from map[%p][%p] ok" , obj , map_direct_prop )
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "travel item[%p] from map[%p][%p] ok , key_id[%"PRIu64"]" , map_node , obj , map_direct_prop , map_node->map_key_id )
	}
	
	if( key )
		(*key) = (map_node?map_node->key:NULL) ;
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	return (map_node?0:1);
}

ZlangInvokeFunction ZlangInvokeFunction_map_TravelNextKey_object;
int ZlangInvokeFunction_map_TravelNextKey_object( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject		*in1_obj = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	int				nret = 0 ;
	
	nret = map_TravelNextKey( rt , obj , & in1_obj ) ;
	if( nret == 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "map_TravelNextKey return[%d]" , nret )
	}
	else if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "map_TravelNextKey failed[%d]" , nret )
		return ThrowFatalException( rt , nret , EXCEPTION_MESSAGE_GENERAL_ERROR );
	}
	
	if( in1_obj == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "unrefer key object[%p]" , out1_obj )
		UnreferObject( rt , out1_obj );
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "refer key object[%p] from [%p]" , out1_obj , in1_obj )
		nret = ReferObject( rt , out1_obj , in1_obj ) ;
		if( nret )
			return ThrowFatalException( rt , nret , EXCEPTION_MESSAGE_GENERAL_ERROR );
	}
	
	return 0;
}

ZlangDirectFunction_map_TravelPrevKey map_TravelPrevKey;
int map_TravelPrevKey( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject **key )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	struct MapNode			m ;
	struct MapNode			*map_node = NULL ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	if( (*key) == NULL || IsObjectPropertiesEntityNull(*key) )
	{
		map_node = TravelPrevMapTreeNodeByKeyId( map_direct_prop , NULL ) ;
	}
	else
	{
		memset( & m , 0x00 , sizeof(struct MapNode) );
		nret = CalcObjectMapKeyId( rt , (*key) , & (m.map_key_id) ) ;
		if( nret )
		{
			if( key )
				(*key) = NULL ;
			IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
			return ZLANG_ERROR_INVOKE_METHOD_RETURN;
		}
		
		map_node = QueryMapTreeNodeByKeyId( map_direct_prop , & m ) ;
		if( map_node )
		{
			map_node = TravelPrevMapTreeNodeByKeyId( map_direct_prop , map_node ) ;
		}
	}
	if( map_node == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "travel none item from map[%p][%p] ok" , obj , map_direct_prop )
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "travel item[%p] from map[%p][%p] ok , key_id[%"PRIu64"]" , map_node , obj , map_direct_prop , map_node->map_key_id )
	}
	
	if( key )
		(*key) = (map_node?map_node->key:NULL) ;
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	return (map_node?0:1);
}

ZlangInvokeFunction ZlangInvokeFunction_map_TravelPrevKey_object;
int ZlangInvokeFunction_map_TravelPrevKey_object( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject		*in1_obj = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	int				nret = 0 ;
	
	nret = map_TravelPrevKey( rt , obj , & in1_obj ) ;
	if( nret == 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "map_TravelPrevKey return[%d]" , nret )
	}
	else if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "map_TravelPrevKey failed[%d]" , nret )
		return ThrowFatalException( rt , nret , EXCEPTION_MESSAGE_GENERAL_ERROR );
	}
	
	if( in1_obj == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "unrefer key object[%p]" , out1_obj )
		UnreferObject( rt , out1_obj );
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "refer key object[%p] from [%p]" , out1_obj , in1_obj )
		nret = ReferObject( rt , out1_obj , in1_obj ) ;
		if( nret )
			return ThrowFatalException( rt , nret , EXCEPTION_MESSAGE_GENERAL_ERROR );
	}
	
	return 0;
}

ZlangDirectFunction_map_UpdateKey map_UpdateKey;
int map_UpdateKey( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject *old_key , struct ZlangObject *new_key )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	char				*ext_obj_name = NULL ;
	char				*ext_obj2_name = NULL ;
	char				*key_tpye_name = NULL ;
	struct MapNode			m ;
	struct MapNode			*map_node = NULL ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	memset( & m , 0x00 , sizeof(struct MapNode) );
	nret = CalcObjectMapKeyId( rt , old_key , & (m.map_key_id) ) ;
	if( nret )
	{
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_INVOKE_METHOD_RETURN;
	}
	
	ext_obj_name = GetObjectEmbellishName( obj ) ;
	ext_obj2_name = GetObjectEmbellishName2( obj ) ;
	key_tpye_name = GetCloneObjectName( new_key ) ;
	if( ext_obj_name == NULL )
	{
		;
	}
	else if( ext_obj_name && ext_obj2_name == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "map expect two ext objects but one '%s'" , ext_obj_name )
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_SYNTAX;
	}
	else if( ext_obj2_name )
	{
		if( key_tpye_name && STRCMP( ext_obj_name , != , key_tpye_name ) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "object type not matched" )
			IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
			return ZLANG_ERROR_TYPE_OF_OBJECT_NOT_MATCHED;
		}
	}
	
	map_node = QueryMapTreeNodeByKeyId( map_direct_prop , & m ) ;
	if( map_node == NULL )
	{
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return 0;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "unlink item[%p] from map[%p][%p] , old key_id[%"PRIu64"]" , map_node , obj , map_direct_prop , map_node->map_key_id )
	UnlinkMapTreeNode( map_direct_prop , map_node );
	
	UnreferObject( rt , map_node->key );
	ReferObject( rt , map_node->key , new_key );
	
	nret = CalcObjectMapKeyId( rt , new_key , & (map_node->map_key_id) ) ;
	if( nret )
	{
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return nret;
	}
	
	nret = LinkMapTreeNodeByKeyId( map_direct_prop , map_node ) ;
	if( nret )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_INVOKE_METHOD_RETURN , "readd item to map failed[%d] , key_id[%"PRIu64"]" , nret , map_node->map_key_id )
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_INVOKE_METHOD_RETURN;
	}
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "link item[%p] to map[%p][%p] , new key_id[%"PRIu64"]" , map_node , obj , map_direct_prop , map_node->map_key_id )
	
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_map_UpdateKey_object_object;
int ZlangInvokeFunction_map_UpdateKey_object_object( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject		*in1_obj = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*in2_obj = GetInputParameterInLocalObjectStack(rt,2) ;
	int				nret = 0 ;
	
	nret = map_UpdateKey( rt , obj , in1_obj , in2_obj ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "map_UpdateKey failed[%d]" , nret )
	}
	
	return 0;
}

ZlangDirectFunction_map_Remove map_Remove;
int map_Remove( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject **key )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	struct MapNode			m ;
	struct MapNode			*map_node = NULL ;
	struct MapNode			*prev_map_node = NULL ;
	struct MapNode			*next_map_node = NULL ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	memset( & m , 0x00 , sizeof(struct MapNode) );
	nret = CalcObjectMapKeyId( rt , *key , & (m.map_key_id) ) ;
	if( nret )
	{
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return ZLANG_ERROR_INVOKE_METHOD_RETURN;
	}
	
	map_node = QueryMapTreeNodeByKeyId( map_direct_prop , & m ) ;
	if( map_node == NULL )
	{
		(*key) = NULL ;
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return 0;
	}
	prev_map_node = TravelPrevMapTreeNodeByKeyId( map_direct_prop , map_node ) ;
	next_map_node = TravelMapTreeNodeByKeyId( map_direct_prop , map_node ) ;
	
	UnlinkMapTreeNode( map_direct_prop , map_node );
	FreeMapNode( map_node );
	
	map_direct_prop->map_length--;
	
	if( next_map_node )
	{
		/*
		nret = ReferObject( rt , *key , next_map_node->key ) ;
		if( nret )
			return nret;
		*/
		(*key) = next_map_node->key ;
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return 1;
	}
	else if( prev_map_node )
	{
		/*
		nret = ReferObject( rt , *key , prev_map_node->key ) ;
		if( nret )
			return nret;
		*/
		(*key) = prev_map_node->key ;
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return -1;
	}
	else
	{
		(*key) = NULL ;
		IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
		return 0;
	}
}

ZlangInvokeFunction ZlangInvokeFunction_map_Remove_object;
int ZlangInvokeFunction_map_Remove_object( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject		*in1_obj = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	int				nret = 0 ;
	
	nret = map_Remove( rt , obj , & in1_obj ) ;
	if( nret == 0 )
		CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , FALSE );
	else
		CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , TRUE );
	
	return 0;
}

ZlangDirectFunction_map_RemoveAll map_RemoveAll;
int map_RemoveAll( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	DestroyMapTree( map_direct_prop );
	map_direct_prop->map_length = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_map_RemoveAll;
int ZlangInvokeFunction_map_RemoveAll( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	int		nret = 0 ;
	
	nret = map_RemoveAll( rt , obj ) ;
	if( nret )
		return ThrowFatalException( rt , nret , EXCEPTION_MESSAGE_GENERAL_ERROR );
	else
		return 0;
}

ZlangDirectFunction_map_Length map_Length;
int map_Length( struct ZlangRuntime *rt , struct ZlangObject *obj , int32_t *map_length )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	(*map_length) = map_direct_prop->map_length ;
	
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_map_Length;
int ZlangInvokeFunction_map_Length( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	int32_t					map_length ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	map_Length( rt , obj , & map_length );
	CallRuntimeFunction_int_SetIntValue( rt , out1_obj , map_length );
	
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_map_IsEmpty;
int ZlangInvokeFunction_map_IsEmpty( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_map		*map_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	int				nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	if( map_direct_prop->map_length == 0 )
		CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , TRUE );
	else
		CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , FALSE );
	
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_map_IsNotEmpty;
int ZlangInvokeFunction_map_IsNotEmpty( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_map		*map_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1_obj = GetOutputParameterInLocalObjectStack(rt,1) ;
	int					nret = 0 ;
	
	IF_ATOMIC_OBJECT_THEN_LOCK( obj )
	
	if( map_direct_prop->map_length != 0 )
		CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , TRUE );
	else
		CallRuntimeFunction_bool_SetBoolValue( rt , out1_obj , FALSE );
	
	IF_ATOMIC_OBJECT_THEN_UNLOCK( obj );
	
	return 0;
}
ZlangCreateDirectPropertyFunction ZlangCreateDirectProperty_map;
void *ZlangCreateDirectProperty_map( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_map	*map_direct_prop = NULL ;
	
	map_direct_prop = (struct ZlangDirectProperty_map *)ZLMALLOC( sizeof(struct ZlangDirectProperty_map) ) ;
	if( map_direct_prop == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for entity" )
		return NULL;
	}
	memset( map_direct_prop , 0x00 , sizeof(struct ZlangDirectProperty_map) );
	
	return (struct ZlangEntity *)map_direct_prop;
}

ZlangDestroyDirectPropertyFunction ZlangDestroyDirectProperty_map;
void ZlangDestroyDirectProperty_map( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	
	DestroyMapTree( map_direct_prop );
	map_direct_prop->map_length = 0 ;
	
	ZLFREE( map_direct_prop );
	
	return;
}

ZlangSummarizeDirectPropertySizeFunction ZlangSummarizeDirectPropertySize_map;
void ZlangSummarizeDirectPropertySize_map( struct ZlangRuntime *rt , struct ZlangObject *obj , size_t *summarized_obj_size , size_t *summarized_direct_prop_size )
{
	struct ZlangDirectProperty_map	*map_direct_prop = GetObjectDirectProperty(obj) ;
	struct MapNode			*map_node = NULL ;
	
	map_node = NULL ;
	while( ( map_node = TravelMapTreeNodeByKeyId(map_direct_prop,map_node) ) )
	{
		SummarizeObjectSize( rt , map_node->key , summarized_obj_size , summarized_direct_prop_size );
		SummarizeObjectSize( rt , map_node->value , summarized_obj_size , summarized_direct_prop_size );
		SUMMARIZE_SIZE( summarized_obj_size , sizeof(struct MapNode) )
	}
	
	SUMMARIZE_SIZE( summarized_direct_prop_size , sizeof(struct ZlangDirectProperty_map) )
	
	return;
}

static struct ZlangDirectFunctions direct_funcs_map =
	{
		ZLANG_OBJECT_map ,
		
		ZlangCreateDirectProperty_map ,
		ZlangDestroyDirectProperty_map ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		ZlangSummarizeDirectPropertySize_map ,
	} ;

ZlangImportObjectFunction ZlangImportObject_map;
struct ZlangObject *ZlangImportObject_map( struct ZlangRuntime *rt )
{
	struct ZlangObject	*obj = NULL ;
	struct ZlangFunction	*func = NULL ;
	int			nret = 0 ;
	
	nret = ImportObject( rt , & obj , ZLANG_OBJECT_map , & direct_funcs_map , sizeof(struct ZlangDirectFunctions) , NULL ) ;
	if( nret )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_LINK_FUNC_TO_ENTITY , "import object to global objects heap" )
		return NULL;
	}
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Put_object_object , ZLANG_OBJECT_bool , "Put" , ZLANG_OBJECT_object,NULL , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Put_object_object , ZLANG_OBJECT_bool , "Put" , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Put_object_object , ZLANG_OBJECT_bool , "Put" , ZLANG_OBJECT_int,NULL , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Get_object , ZLANG_OBJECT_object , "Get" , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Get_object , ZLANG_OBJECT_object , "Get" , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Get_object , ZLANG_OBJECT_object , "Get" , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_TravelNextKey_object , ZLANG_OBJECT_object , "TravelNextKey" , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_TravelPrevKey_object , ZLANG_OBJECT_object , "TravelPrevKey" , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_UpdateKey_object_object , ZLANG_OBJECT_void , "UpdateKey" , ZLANG_OBJECT_object,NULL , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_UpdateKey_object_object , ZLANG_OBJECT_void , "UpdateKey" , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_UpdateKey_object_object , ZLANG_OBJECT_void , "UpdateKey" , ZLANG_OBJECT_int,NULL , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Remove_object , ZLANG_OBJECT_bool , "Remove" , ZLANG_OBJECT_object,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Remove_object , ZLANG_OBJECT_bool , "Remove" , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Remove_object , ZLANG_OBJECT_bool , "Remove" , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_RemoveAll , ZLANG_OBJECT_void , "RemoveAll" , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_Length , ZLANG_OBJECT_int , "Length" , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_IsEmpty , ZLANG_OBJECT_bool , "IsEmpty" , NULL ) ;
	if( func == NULL )
		return NULL;
	
	func = AddFunctionAndParametersInObject( rt , obj , ZlangInvokeFunction_map_IsNotEmpty , ZLANG_OBJECT_bool , "IsNotEmpty" , NULL ) ;
	if( func == NULL )
		return NULL;
	
	SetRuntimeFunction_map_Put( rt , map_Put );
	SetRuntimeFunction_map_Get( rt , map_Get );
	SetRuntimeFunction_map_TravelNextKey( rt , map_TravelNextKey );
	SetRuntimeFunction_map_TravelPrevKey( rt , map_TravelPrevKey );
	SetRuntimeFunction_map_UpdateKey( rt , map_UpdateKey );
	SetRuntimeFunction_map_Remove( rt , map_Remove );
	SetRuntimeFunction_map_RemoveAll( rt , map_RemoveAll );
	SetRuntimeFunction_map_Length( rt , map_Length );
	
	return obj ;
}

